var input = File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "..", "day4.txt"));
IEnumerable> Parse(string[] raw) {
var e = raw.GetEnumerator();
var dict = new Dictionary();
while(e.MoveNext()){
var line = (string)e.Current;
if (string.IsNullOrEmpty(line))
{
yield return dict;
dict = new Dictionary();
continue;
}
var items = line.Split(' ');
foreach (var item in items)
{
var parts = item.Split(':');
dict.Add(parts[0], parts[1]);
}
}
yield return dict;
}
var passports = Parse(input);
var required = new[] { "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid" };
bool isValid(Dictionary passport) => required.All(r => passport.ContainsKey(r));
var part1 = passports.Count(isValid);
part1.Dump();
var fields = new Dictionary> {
{ "byr", i => { var n = int.Parse(i); return n >= 1920 && n <= 2002; }},
{ "iyr", i => { var n = int.Parse(i); return n >= 2010 && n <= 2020; }},
{ "eyr", i => { var n = int.Parse(i); return n >= 2020 && n <= 2030; }},
{ "hgt", i => { var m = Regex.Match(i, @"^(\d+)(cm|in)$"); return m.Success && int.TryParse(m.Groups[1].Value, out int n) && (m.Groups[2].Value == "cm" ? n >= 150 && n <= 193 : n>=59 && n <=76 ); }},
{ "hcl", i => { return Regex.IsMatch(i, @"^#[0-9a-f]{6}$"); }},
{ "ecl", i => { return i == "amb" || i == "blu" || i == "brn" || i == "gry" || i == "grn" || i == "hzl" || i == "oth"; }},
{ "pid", i => { return Regex.IsMatch(i, @"^\d{9}$"); }},
};
bool isValidPartTwo (Dictionary passport) => fields.All(f => passport.ContainsKey(f.Key) && f.Value(passport[f.Key]));
var part2 = passports.Count(isValidPartTwo);
part2.Dump();